package com.ruibang.glass.quality.service.impl;

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruibang.glass.common.constants.Constants;
import com.ruibang.glass.common.constants.RedisKey;
import com.ruibang.glass.common.domain.quality.BcStationHqDetail;
import com.ruibang.glass.common.domain.quality.GlassBindTest;
import com.ruibang.glass.common.utils.DateUtils;
import com.ruibang.glass.quality.domain.resp.GlassBindResp;
import com.ruibang.glass.quality.domain.resp.GlassHqInfo;
import com.ruibang.glass.quality.entity.Defect;
import com.ruibang.glass.quality.mapper.DefectMapper;
import com.ruibang.glass.quality.mapper.ShelfLotItemMapper;
import com.ruibang.glass.quality.service.GlassStationService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

@Slf4j
@Service
public class GlassStationServiceImpl extends ServiceImpl<DefectMapper, Defect> implements GlassStationService, ApplicationRunner {

    public static final Map<String, String> NEW_MAPPER_OLD_MAP = new HashMap<>();
    public static final Map<String, String> OLD_MAPPING_NEW_MAP = new HashMap<>();

    @Autowired
    private ShelfLotItemMapper shelfLotItemMapper;

    @Autowired
    @Qualifier("myRedisTemplate")
    private RedisTemplate<String, Object> redisTemplate;

    /**
     * @Description: 根据冷端id获取最新的热端id
     * @version v1.0
     * @author songJinKang
     * @date 2023-09-18 17:53
     */
    @Override
    public String getHotGlassId(String newGlassId) {
        //获取热端玻璃Id
        String oldId = NEW_MAPPER_OLD_MAP.get(newGlassId);
        if (StringUtils.isNotBlank(oldId)) {
            return getHotGlassId(oldId);
        } else {
            return newGlassId;
        }
    }


    /**
     * @Description: 根据热端玻璃ID获取冷端玻璃ID
     * @version v1.0
     * @author songJinKang
     * @date 2024-01-11 17:33
     */
    @Override
    public List<String> getColdGlassId(List<String> oldGlassIds) {
        List<String> data = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(oldGlassIds)) {
            for (String oldGlassId : oldGlassIds) {
                recursionColdGlassId(oldGlassId, data);
            }
        }
        return data;
    }

    @Override
    public Map<String, LocalDateTime> getColdGlassIdMappingStationStartTime(List<String> newGlassIds) {
        Map<String, LocalDateTime> dataMap = new ConcurrentHashMap<>();
        //获取热端玻璃ID
        for (String newGlassId : newGlassIds) {
            String hotGlassId = getHotGlassId(newGlassId);
            if (StringUtils.isNotBlank(hotGlassId)) {
                Object timeObj = redisTemplate.opsForHash().get(RedisKey.HOT_ID_MAPPING_STATION_START_TIME_KEY, hotGlassId);
                if (timeObj != null && StringUtils.isNotBlank(timeObj.toString())) {
                    LocalDateTime localDateTime = DateUtils.stringToLocalDateTime(timeObj.toString(), Constants.DATE_TIME_FORMATTER_STR);
                    dataMap.put(newGlassId.substring(6), localDateTime);
                }
            }
        }

        return dataMap;
    }


    @Override
    public Map<String, LocalDateTime> getColdGlassIdMappingStationStartTime(List<GlassHqInfo> hqDetailByDate, List<String> coldGlassIds) {
        Map<String, LocalDateTime> dataMap = new ConcurrentHashMap<>();
        if (CollectionUtils.isNotEmpty(coldGlassIds)) {
            Map<String, LocalDateTime> hqDetailMap = hqDetailByDate.stream().collect(Collectors.toMap(GlassHqInfo::getGlassId, GlassHqInfo::getStationStartTime));
            for (String coldGlassId : coldGlassIds) {
                String hotGlassId = this.getHotGlassId(coldGlassId);
                if (StringUtils.isNotBlank(hotGlassId)) {
                    LocalDateTime stationStartTime = hqDetailMap.get(hotGlassId);
                    if (stationStartTime != null) {
                        dataMap.put(coldGlassId.substring(6), stationStartTime);
                    } else {
                        log.error("根据热端ID ：{}  未获取到横切时间", hotGlassId);
                    }
                } else {
                    log.error("根据冷端ID ：{}  未获取到热端玻璃ID", coldGlassId);
                }
            }
        }
        return dataMap;
    }

    @Override
    public Map<String, LocalDateTime> getHotGlassIdMappingStationStartTime(List<String> hotIds) {
        Map<String, LocalDateTime> map = new HashMap<>();
        for (String hotId : hotIds) {
            Object timeObj = redisTemplate.opsForHash().get(RedisKey.HOT_ID_MAPPING_STATION_START_TIME_KEY, hotId);
            if (timeObj != null && StringUtils.isNotBlank(timeObj.toString())) {
                LocalDateTime localDateTime = DateUtils.stringToLocalDateTime(timeObj.toString(), Constants.DATE_TIME_FORMATTER_STR);
                map.put(hotId, localDateTime);
            }
        }
        return map;
    }

    @Override
    public Map<String, String> getColdIdMappingHotId(List<String> coldIds) {
        Map<String, String> map = new HashMap<>(16);
        if (CollectionUtils.isNotEmpty(coldIds)) {
            for (String coldId : coldIds) {
                map.put(coldId, this.getHotGlassId(coldId));
            }
        }
        return map;
    }

    @Override
    public void addHqInfoCache(BcStationHqDetail bcStationHqDetail) {
        if (bcStationHqDetail != null) {
            if (StringUtils.isNotBlank(bcStationHqDetail.getId()) && bcStationHqDetail.getStationStartTime() != null) {
                redisTemplate.convertAndSend(RedisKey.REDIS_BC_STATION_HQ_DETAIL_TOPIC, bcStationHqDetail);
            }
        }
    }

    @Override
    public void addGlassBindTestCache(GlassBindTest glassBindTest) {
        if (glassBindTest != null && StringUtils.isNotBlank(glassBindTest.getNewID()) && StringUtils.isNotBlank(glassBindTest.getOldID())) {
            redisTemplate.convertAndSend(RedisKey.REDIS_GLASS_BIND_TEST_TOPIC, glassBindTest);
        }
    }


    @Override
    public void run(ApplicationArguments args) throws Exception {
        //初始化bindData
        CompletableFuture.runAsync(this::processBindData);
    }


    @Scheduled(cron = "0 0/30 * * * ?")
    public void bindDataTask() {
        processBindData();
    }

    private void processBindData() {
        //玻璃新旧ID绑定关系
        NEW_MAPPER_OLD_MAP.clear();
        OLD_MAPPING_NEW_MAP.clear();
        List<GlassBindResp> coldGlassBindResp = shelfLotItemMapper.getNewIdGlassBindAll();
        ArrayList<GlassBindResp> filterData = coldGlassBindResp.stream().collect(Collectors.collectingAndThen(
                Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(GlassBindResp::getOldId))),
                ArrayList::new
        )).stream().collect(Collectors.collectingAndThen(
                Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(GlassBindResp::getNewId))),
                ArrayList::new
        ));
        Map<String, String> newMappingOldMap = filterData.stream().collect(Collectors.toMap(GlassBindResp::getNewId, GlassBindResp::getOldId));
        NEW_MAPPER_OLD_MAP.putAll(newMappingOldMap);

        Map<String, String> oldMappingNewMap = filterData.stream().collect(Collectors.toMap(GlassBindResp::getOldId, GlassBindResp::getNewId));
        OLD_MAPPING_NEW_MAP.putAll(oldMappingNewMap);

        //横切信息
        redisTemplate.delete(RedisKey.HOT_ID_MAPPING_STATION_START_TIME_KEY);
        List<GlassHqInfo> hqDetailAll = shelfLotItemMapper.getHqDetailAll();
        Map<String, String> hqDetailMap = hqDetailAll.stream().collect(Collectors.toMap(GlassHqInfo::getGlassId, e -> e.getStationStartTime().format(Constants.DATE_TIME_FORMATTER)));
        redisTemplate.opsForHash().putAll(RedisKey.HOT_ID_MAPPING_STATION_START_TIME_KEY, hqDetailMap);

    }


    private void recursionColdGlassId(String oldGlassId, List<String> data) {
        //获取冷端玻璃ID
        String nweId = OLD_MAPPING_NEW_MAP.get(oldGlassId);
        if (StringUtils.isNotBlank(nweId)) {
            data.add(nweId);
            recursionColdGlassId(nweId, data);
        }
    }


}